package com.base.commons.tools.utils;

import org.icepdf.core.exceptions.PDFException;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.util.GraphicsRenderingHints;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;


/**
 * Description: msc 图片处理相关工具类
 * Created by Abel
 * Date: 2018/6/19 10:05
 */
@Component
public class ImageUtil {

    public static BASE64Encoder encoder = new BASE64Encoder();
    public static BASE64Decoder decoder = new BASE64Decoder();

    static Map<String,String> imageTypeMap = null;
    static {
        imageTypeMap =new HashMap<>();
        imageTypeMap.put("FFD8FF","jpg");
        imageTypeMap.put("89504E","png");
        imageTypeMap.put("255044", "pdf");
        imageTypeMap.put("474946","gif");
        imageTypeMap.put("524946","webp");
        imageTypeMap.put("000001","ico");
        imageTypeMap.put("424D36","bmp");
        imageTypeMap.put("00000A","tga");
        imageTypeMap.put("49492A","tif");
    }


    /**
     * 将PDF转换成base64编码
     */
   public static String getPDFBinary(File file) {
        FileInputStream fin = null;
        BufferedInputStream bin = null;
        ByteArrayOutputStream baos = null;
        BufferedOutputStream bout = null;
        try {
            //建立读取文件的文件输出流
            fin = new FileInputStream(file);
            //在文件输出流上安装节点流（更大效率读取）
            bin = new BufferedInputStream(fin);
            // 创建一个新的 byte 数组输出流，它具有指定大小的缓冲区容量
            baos = new ByteArrayOutputStream();
            //创建一个新的缓冲输出流，以将数据写入指定的底层输出流
            bout = new BufferedOutputStream(baos);
            byte[] buffer = new byte[1024];
            int len = bin.read(buffer);
            while (len != -1) {
                bout.write(buffer, 0, len);
                len = bin.read(buffer);
            }
            //刷新此输出流并强制写出所有缓冲的输出字节，必须这行代码，否则有可能有问题
            bout.flush();
            byte[] bytes = baos.toByteArray();
            //pdfByteToImag(bytes);
            //sun公司的API
            return encoder.encodeBuffer(bytes).trim();
            //apache公司的API
            //return Base64.encodeBase64String(bytes);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fin!=null) {
                    fin.close();
                }
                if(bin!=null) {
                    bin.close();
                }
                //关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用，而不会产生任何 IOException
                //baos.close();
                if(bout!=null){
                    bout.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将base64编码转换成PDF
     */
    public static String base64StringToPDF(String base64sString) {
        BufferedInputStream bin = null;
        FileOutputStream fout = null;
        BufferedOutputStream bout = null;
        try {
            //将base64编码的字符串解码成字节数组
            byte[] bytes = decoder.decodeBuffer(base64sString);
            //apache公司的API
            //byte[] bytes = Base64.decodeBase64(base64sString);
            //创建一个将bytes作为其缓冲区的ByteArrayInputStream对象
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            //创建从底层输入流中读取数据的缓冲输入流对象
            bin = new BufferedInputStream(bais);
            //指定输出的文件
            //将pdf字节流输出到文件流
            String path = FileUtil.rootPath()+ File.separator +"fbg-ods"+File.separator+ "pdfFileBase64";
            File fil = new File(path);
            if (!fil.exists()){
                fil.mkdirs();
            }
            String pdfName = path+ File.separator + DateUtils.getDateStr() + ".pdf";
            File file = new File(pdfName);
            //创建到指定文件的输出流
            fout = new FileOutputStream(file);
            //为文件输出流对接缓冲输出流对象
            bout = new BufferedOutputStream(fout);

            byte[] buffers = new byte[1024];
            int len = bin.read(buffers);
            while (len != -1) {
                bout.write(buffers, 0, len);
                len = bin.read(buffers);
            }
            //刷新此输出流并强制写出所有缓冲的输出字节，必须这行代码，否则有可能有问题
            bout.flush();
            return pdfName;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(bin!=null){
                    bin.close();
                }
                if(fout!=null){
                    fout.close();
                }
               if(bout!=null){
                   bout.close();
               }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /***
     * PDF转图片
     * @param filePath
     */
    public static String pdf2Image(String filePath) throws IOException, PDFException, PDFSecurityException, InterruptedException {
        // String filePath = "c:/test.pdf";
        Document document = new Document();
        document.setFile(filePath);
        float scale = 2.5f;//缩放比例
        float rotation = 0f;//旋转角度

        for (int i = 0; i < document.getNumberOfPages(); i++) {
            BufferedImage image = (BufferedImage)
                    document.getPageImage(i, GraphicsRenderingHints.SCREEN, org.icepdf.core.pobjects.Page.BOUNDARY_CROPBOX, rotation, scale);
            RenderedImage rendImage = image;
            try {
                String path = FileUtil.rootPath()+ File.separator +"fbg-ods"+File.separator+ "pdfFile"+"img";
                File file1 = new File(path);
                if (!file1.exists()){
                    file1.mkdirs();
                }
                File file = new File(path+ File.separator + DateUtils.getDateStr()+ ".png");
                ImageIO.write(rendImage, "png", file);
                return file.toString();
            } catch (IOException e) {
            }
            image.flush();
        }
        document.dispose();
        return null;
    }

    /***
     * PDF转图片
     * @param bytes
     */
    public static byte[] pdf2Image(byte[] bytes) throws IOException, PDFException, PDFSecurityException, InterruptedException {
        Document document = new Document();
        ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
        try {
            document.setByteArray(bytes, 0, bytes.length, null);
            float scale = 2.5f;//缩放比例
            float rotation = 0f;//旋转角度

            for (int i = 0; i < document.getNumberOfPages(); i++) {
                BufferedImage image = (BufferedImage)
                        document.getPageImage(i, GraphicsRenderingHints.SCREEN, org.icepdf.core.pobjects.Page.BOUNDARY_CROPBOX, rotation, scale);
                RenderedImage rendImage = image;
                ImageIO.write(rendImage, "png", pngOut);
                image.flush();

                return pngOut.toByteArray();
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (document != null) {
                    document.dispose();
                }
                if (pngOut != null) {
                    pngOut.close();
                }
            } catch (Exception e1){
                e1.printStackTrace();
            }
        }
        return null;
    }


    /**
     * PDF文件和图片上传腾讯云后删除本地文件
     * @param path
     */
    public static void deleteFile(String path) {
        File file = new File(path);
        if (file.exists()){
            file.delete();
        }
    }


    /**
     * 获取图片宽度和高度
     * @param
     * @return 返回图片的宽度
     */
    public static int[] getImgWidthHeight(File file) {
        InputStream is = null;
        BufferedImage src = null;
        int[] result = { 0, 0 };
        try {
            // 获得文件输入流
            is = new FileInputStream(file);
            // 从流里将图片写入缓冲图片区
            src = ImageIO.read(is);
            result[0] =src.getWidth(null); // 得到源图片宽
            result[1] =src.getHeight(null);// 得到源图片高
            is.close();  //关闭输入流
        } catch (Exception ef) {
            ef.printStackTrace();
        }

        return result;
    }


    /**
     *  拼接电子签名图片（注：电子签名图片需长宽一致）
     * @param files     img1 ，img2
     * @param type      1：横向拼接  2：纵向拼接
     * @param targetFile  合成新的图片地址
     */
    public static void mergeImage(String[] files, int type, String targetFile) {
        int len = files.length;
        if (len < 1) {
            throw new RuntimeException("图片数量小于1");
        }
        File[] src = new File[len];
        BufferedImage[] images = new BufferedImage[len];
        int[][] ImageArrays = new int[len][];
        for (int i = 0; i < len; i++) {
            try {
                src[i] = new File(files[i]);
                images[i] = ImageIO.read(src[i]);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int width = images[i].getWidth();
            int height = images[i].getHeight();
            ImageArrays[i] = new int[width * height];
            ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);
        }
        int newHeight = 0;
        int newWidth = 0;
        for (int i = 0; i < images.length; i++) {
            // 横向
            if (type == 1) {
                newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
                newWidth += images[i].getWidth();
            } else if (type == 2) {// 纵向
                newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
                newHeight += images[i].getHeight();
            }
        }
        if (type == 1 && newWidth < 1) {
            return;
        }
        if (type == 2 && newHeight < 1) {
            return;
        }

        // 生成新图片
        try {
            BufferedImage ImageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            int height_i = 0;
            int width_i = 0;
            for (int i = 0; i < images.length; i++) {
                if (type == 1) {
                    ImageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0,
                            images[i].getWidth());
                    width_i += images[i].getWidth();
                } else if (type == 2) {
                    ImageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);
                    height_i += images[i].getHeight();
                }
            }
            //输出想要的图片
            ImageIO.write(ImageNew, targetFile.split("\\.")[1], new File(targetFile));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     *  根据图片像素位置添加用户电子签名
     * @param bigPath
     * @param smallPath
     * @param outFile
     */
    public static final void overlapImage(String bigPath, String smallPath,Integer width,Integer height, String outFile) {
        try {
            BufferedImage big = ImageIO.read(new File(bigPath));
            BufferedImage small = ImageIO.read(new File(smallPath));
            Graphics2D g = big.createGraphics();

            int newWidth = (big.getWidth() - small.getWidth()) / 2;
            int newHeight = (big.getHeight() - small.getHeight()) / 2;

            System.err.println("newWidth =" + newWidth + ",newHeight =" + newHeight);
            //根据图片像素位置粘贴带电子签名
            g.drawImage(small, width, height, small.getWidth(), small.getHeight(), null);
            g.dispose();
            ImageIO.write(big, outFile.split("\\.")[1], new File(outFile));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     *
     * @param urlStr 远程文件地址
     * @return 转换为base64
     */
    public static String downImageByUrl(String urlStr,String imageName)throws IOException{
        URL url = new URL(urlStr);
        URLConnection conn = url.openConnection();
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        InputStream readStream = null;
        ByteArrayOutputStream baos = null;
        BufferedOutputStream bout = null;
        try {
            readStream = conn.getInputStream();
            int i = conn.getContentLength();
            if(i == 0){
                throw new DownImageByUrlException("面单内容为空，请重新上传");
            }
            //在文件输出流上安装节点流（更大效率读取）
            // 创建一个新的 byte 数组输出流，它具有指定大小的缓冲区容量
            baos = new ByteArrayOutputStream();
            //创建一个新的缓冲输出流，以将数据写入指定的底层输出流
            bout = new BufferedOutputStream(baos);
            byte[] buffer = new byte[1024];
            int len = readStream.read(buffer);
            String imageCode = bytesToHexString(buffer);
            String imageType = imageTypeMap.get(imageCode);
            if(!imageName.equalsIgnoreCase(imageType) || !urlStr.toLowerCase().endsWith(imageName.toLowerCase())){
                throw new DownImageByUrlException("面单类型和实际面单格式不一致，请重新上传");
            }
            while (len != -1) {
                bout.write(buffer, 0, len);
                len = readStream.read(buffer);
            }
            bout.flush();
            byte[] bytes = baos.toByteArray();
            String base64ImageStr = encoder.encodeBuffer(bytes).trim();
            return base64ImageStr;
        }finally {
            //刷新此输出流并强制写出所有缓冲的输出字节，必须这行代码，否则有可能有问题
            if(bout != null){
                bout.close();
            }
            if(baos != null){
                baos.close();
            }
            if(readStream != null){
                readStream.close();
            }
        }
    }

    public static class DownImageByUrlException extends RuntimeException{

        private String code;

        private String errorMessage;

        public DownImageByUrlException(String code, String message) {
            this.code = code;
            this.errorMessage = message;
        }
        public DownImageByUrlException(String message) {
            this.errorMessage = message;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public String getErrorMessage() {
            return errorMessage;
        }

        public void setMessage(String message) {
            this.errorMessage = message;
        }
    }

    private  static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < 3; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }


    public static void main(String[] args) throws Exception{
        String base64 = downImageByUrl("http://192.168.109.128:8081/oms/common/2020/08/07/01/5769361606034230806ef4b415356001.png","png");
        System.out.println(base64);
    }


}


